﻿//----------------------------------------------------------------
// Copyright (c) 2011-2013 
// All rights reserved.
// Author: Ben DaoWei 
// Contact: bendaowei@gmail.com
// Web Link: http://xnaeditor.codeplex.com
// ----------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine.IO;
using System.IO;
using Microsoft.Xna.Framework.Graphics;
using UnityEngine.Graphics.Shader;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics.PackedVector;
using Microsoft.Xna.Framework.Content;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using UnityEngine.Gameplay;
using UnityEngine.Gameplay.Match;

namespace UnityEngine.Graphics.Texture
{
    public class TextureManager : IDisposable
    {
        private TextureManager()
        {
            // do nothing
        }

        ~TextureManager()
        {
            this.Dispose(false);
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        public static void SingletonDispose()
        {
            if (_Instance != null)
                _Instance.Dispose();
            _Instance = null;
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_TextureDictionary != null)
                {
                    foreach (var element in _TextureDictionary.Values)
                        element.Dispose();
                }
            }
        }

        private static TextureManager _Instance;
        public static TextureManager Instance
        {
            get
            {
                if (_Instance == null)
                    _Instance = new TextureManager();
                return _Instance;
            }
        }

        private Dictionary<string, Texture2D> _TextureDictionary = new Dictionary<string, Texture2D>();

        public void Reset()
        {
            _TextureDictionary = new Dictionary<string, Texture2D>();
        }

        private void GenerateBitmap(GraphicsDevice device, int width, int height)
        {
            background = new Texture2D(device, width, height);
        }

        byte[] bmpBytes;
        Texture2D background;
        int width, height;
        public Texture2D ConvertBitmapToTexture(Bitmap b)
        {
            if (background == null ||
                b.Width != background.Width ||
                b.Height != background.Height)
            {
                width = b.Width;
                height = b.Height;
                GenerateBitmap(EffectManager.Instance.GraphicsDevice, width, height);
            }

            BitmapData bData = b.LockBits(new System.Drawing.Rectangle(new System.Drawing.Point(), b.Size),
                ImageLockMode.ReadOnly,
                PixelFormat.Format32bppRgb);

            // number of bytes in the bitmap  
            int byteCount = bData.Stride * b.Height;
            if (bmpBytes == null ||
                bmpBytes.Length != byteCount)
                bmpBytes = new byte[byteCount];

            // Copy the locked bytes from memory  
            Marshal.Copy(bData.Scan0, bmpBytes, 0, byteCount);

            // don't forget to unlock the bitmap!!  
            b.UnlockBits(bData);

            background.SetData(bmpBytes);

            return background;
        }

        private bool CopyMode = false;
        private bool TryCopy(string directory, string path)
        {
            string filePath = GetFilePath(path);

            string newPath = directory + "\\" + path;
            newPath = newPath.Replace(".png", ".blp");
            if (Path.HasExtension(newPath) == false)
                newPath += ".blp";
            if (File.Exists(filePath) == false && File.Exists(newPath) == true)
            {
                File.Copy(newPath, filePath);
                return true;
            }
            if (File.Exists(filePath))
                return true;
            return false;
        }

        private string GetFilePath(string path)
        {
            string filePath = IOManager.Instance.AssetsFolder + "\\" + path;
            filePath = filePath.Replace(".png", ".blp");
            if (Path.HasExtension(filePath) == false)
                filePath += ".blp";
            return filePath;
        }

        private static void PreMultiplyAlphas(Texture2D ret)
        {
            Byte4[] data = new Byte4[ret.Width * ret.Height];
            ret.GetData<Byte4>(data);
            for (int i = 0; i < data.Length; i++)
            {
                Vector4 vec = data[i].ToVector4();
                float alpha = vec.W / 255.0f;
                int a = (int)(vec.W);
                int r = (int)(alpha * vec.X);
                int g = (int)(alpha * vec.Y);
                int b = (int)(alpha * vec.Z);
                uint packed = (uint)((a << 24) + (b << 16) + (g << 8) + r);

                data[i].PackedValue = packed;
            }
            ret.SetData<Byte4>(data);
        }

        public Texture2D GetTexture(string path)
        {
            if (_TextureDictionary.ContainsKey(path))
                return _TextureDictionary[path];

            string filePath = this.GetFilePath(path);
            filePath = filePath.Replace(".blp", ".png");
            if (Path.HasExtension(filePath) == false)
                filePath += ".png";

            using (FileStream fs = new FileStream(filePath, FileMode.Open))
            {
                Texture2D temp = Texture2D.FromStream(EffectManager.Instance.GraphicsDevice, fs);
                //PreMultiplyAlphas(temp);
                _TextureDictionary.Add(path, temp);
                fs.Close();
                return temp;
            }

            //string filePath = GetFilePath(path);
            //if (CopyMode)
            //{
            //    if (TryCopy("D:\\WorkCopy1", path) == false)
            //    {
            //        if (TryCopy("D:\\WorkCopy0", path) == false)
            //            throw new Exception("Can't find file.");
            //    }
            //}
            //using (FileStream fs = new FileStream(filePath, FileMode.Open))
            //{
            //    fs.Position = 0;
            //    Bitmap bitmap = BlpConverter.GetImageFromBlpFile(fs);
            //    if (bitmap == null)
            //    {
            //        int breakpont = 0;
            //        return null;
            //    }
            //    Texture2D temp = this.ConvertBitmapToTexture(bitmap);
            //    _TextureDictionary.Add(path, temp);
            //    fs.Close();
            //}

            //filePath = filePath.Replace(".blp", ".png");
            //if (Path.HasExtension(filePath) == false)
            //    filePath += ".png";
            //try
            //{
            //    using (FileStream fs = new FileStream(filePath, FileMode.Open))
            //    {
            //        Texture2D temp = Texture2D.FromStream(EffectManager.Instance.GraphicsDevice, fs);
            //        _TextureDictionary.Add(path, temp);
            //        fs.Close();
            //    }
            //}
            //catch (System.Exception ex)
            //{
            //    filePath = filePath.Replace(".png", ".bmp");
            //    using (FileStream fs = new FileStream(filePath, FileMode.Open))
            //    {
            //        Texture2D temp = Texture2D.FromStream(EffectManager.Instance.GraphicsDevice, fs);
            //        _TextureDictionary.Add(path, temp);
            //        fs.Close();
            //    }
            //}

            return _TextureDictionary[path];
        }

        //private const string TEXTURE_REPLACABLE_RED = "ReplaceableTextures\\TeamColor\\TeamColor00.blp";
        private const string TEXTURE_REPLACABLE_TEAM_COLOR = "ReplaceableTextures\\TeamColor\\TeamColor0{0}.blp";
        private const string TEXTURE_REPLACABLE_TEAM_GLOW = "ReplaceableTextures\\TeamGlow\\TeamGlow0{0}.blp";
        private const string REPLACABLE_TEXTURE_CLIFF0 = "ReplaceableTextures\\Cliff\\C_Cliff0.blp";
        private const string REPLACABLE_TEXTURE_CLIFF1 = "ReplaceableTextures\\Cliff\\C_Cliff1.blp";

        private Texture2D _Cliff0;
        private Texture2D _Cliff1;

        private Texture2D[] _TeamGlow = null;
        private Texture2D[] _TeamColor = null;
        public Texture2D[] TeamColor
        {
            get
            {
                if (_TeamColor == null)
                {
                    _TeamColor = new Texture2D[(int)TeamPositionType.Count];
                    for (int i = 0; i < (int)TeamPositionType.Count; i++)
                        _TeamColor[i] = this.GetTexture(string.Format(TEXTURE_REPLACABLE_TEAM_COLOR, i));
                }
                return _TeamColor;
            }
        }
        public Texture2D[] TeamGlow
        {
            get
            {
                if (_TeamGlow == null)
                {
                    _TeamGlow = new Texture2D[(int)TeamPositionType.Count];
                    for (int i = 0; i < (int)TeamPositionType.Count; i++)
                        _TeamGlow[i] = this.GetTexture(string.Format(TEXTURE_REPLACABLE_TEAM_GLOW, i));
                }
                return _TeamGlow;
            }
        }

        public Texture2D Cliff0
        {
            get
            {
                if (_Cliff0 == null)
                    _Cliff0 = GetTexture(REPLACABLE_TEXTURE_CLIFF0);
                return _Cliff0;
            }
        }
        public Texture2D Cliff1
        {
            get
            {
                if (_Cliff1 == null)
                    _Cliff1 = GetTexture(REPLACABLE_TEXTURE_CLIFF1);
                return _Cliff1;
            }
        }
    }
}
